﻿/**
 * Project SEM 2 - SMS for schools
 * File author:ToanMH
 * Datetime create:14/11/2010
 * File version:1.0
 * File description:
 * This class use for list all comport in the computer
 * Modify history:
 * 
 */
using System;
using System.Text;
using ComTypes = System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using System.Collections.Generic;

namespace sms_modem_control
{
public class Win32DeviceMgmt
{
    private const UInt32 DIGCF_PRESENT = 0x00000002;
    private const UInt32 DIGCF_DEVICEINTERFACE = 0x00000010;
    private const UInt32 SPDRP_DEVICEDESC = 0x00000000;
    private const UInt32 DICS_FLAG_GLOBAL = 0x00000001;
    private const UInt32 DIREG_DEV = 0x00000001;
    private const UInt32 KEY_QUERY_VALUE = 0x0001;
    private const string GUID_DEVINTERFACE_COMPORT = "4d36e978-e325-11ce-bfc1-08002be10318";//"86E0D1E0-8089-11D0-9CE4-08003E301F73";
    private const string GUID_DEVINTERFACE_MODEM = "6F686C73-504B-111-9A0B-850C26FDB25F";

    /*
     Popular Device Class GUIDs:
        Class 	    GUID 	                                Device Description
        CDROM 	    4D36E965-E325-11CE-BFC1-08002BE10318 	CD/DVD/Blu-ray drives
        DiskDrive 	4D36E967-E325-11CE-BFC1-08002BE10318 	Hard drives
        Display 	4D36E968-E325-11CE-BFC1-08002BE10318 	Video adapters
        FDC 	    4D36E969-E325-11CE-BFC1-08002BE10318 	Floppy controllers
        FloppyDisk 	4D36E980-E325-11CE-BFC1-08002BE10318 	Floppy drives
        HDC 	    4D36E96A-E325-11CE-BFC1-08002BE10318 	Hard drive controllers
        HIDClass 	745A17A0-74D3-11D0-B6FE-00A0C90F57DA 	Some USB devices
        1394 	    6BDD1FC1-810F-11D0-BEC7-08002BE2092F 	IEEE 1394 host controller
        Image 	    6BDD1FC6-810F-11D0-BEC7-08002BE2092F 	Cameras and scanners
        Keyboard 	4D36E96B-E325-11CE-BFC1-08002BE10318 	Keyboards
        Modem 	    4D36E96D-E325-11CE-BFC1-08002BE10318 	Modems
        Mouse 	    4D36E96F-E325-11CE-BFC1-08002BE10318 	Mice and pointing devices
        Media 	    4D36E96C-E325-11CE-BFC1-08002BE10318 	Audio and video devices
        Net 	    4D36E972-E325-11CE-BFC1-08002BE10318 	Network adapters
        Ports 	    4D36E978-E325-11CE-BFC1-08002BE10318 	Serial and parallel ports
        SCSIAdapter 4D36E97B-E325-11CE-BFC1-08002BE10318 	SCSI and RAID controllers
        System 	    4D36E97D-E325-11CE-BFC1-08002BE10318 	System buses, bridges, etc.
        USB 	    36FC9E60-C465-11CF-8056-444553540000 	USB host controllers and hubs
     
     */

    [StructLayout(LayoutKind.Sequential)]
    private struct SP_DEVINFO_DATA
    {
        public Int32  cbSize;
        public Guid   ClassGuid;
        public Int32  DevInst;
        public UIntPtr Reserved;
    };

    [DllImport("setupapi.dll")]
    private static extern Int32 SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);

    [DllImport("setupapi.dll")]
    private static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, Int32 MemberIndex, ref  SP_DEVINFO_DATA DeviceInterfaceData);

    [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetupDiGetDeviceRegistryProperty(IntPtr deviceInfoSet, ref SP_DEVINFO_DATA deviceInfoData,
        uint property, out UInt32 propertyRegDataType, StringBuilder propertyBuffer, uint propertyBufferSize, out UInt32 requiredSize);

    [DllImport("setupapi.dll", SetLastError = true)]
    private static extern IntPtr SetupDiGetClassDevs(ref Guid gClass, UInt32 iEnumerator, IntPtr hParent, UInt32 nFlags);

    [DllImport("Setupapi", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SetupDiOpenDevRegKey(IntPtr hDeviceInfoSet, ref SP_DEVINFO_DATA deviceInfoData, uint scope,
        uint hwProfile, uint parameterRegistryValueKind, uint samDesired);

    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "RegQueryValueExW", SetLastError = true)]
    private static extern int RegQueryValueEx(IntPtr hKey, string lpValueName, int lpReserved, out uint lpType,
        StringBuilder lpData, ref uint lpcbData);

    [DllImport("advapi32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
    private static extern int RegCloseKey(IntPtr hKey);

    [DllImport("kernel32.dll")]
    private static extern Int32 GetLastError();

    public struct DeviceInfo
    {
        public string name;
        public string decsription;
    }

    /// <summary>
    /// Get all comport 
    /// </summary>
    /// <returns>List\<DeviceInfo\></returns>
    public static List<DeviceInfo> GetAllCOMPorts()
    {
        Guid guidComPorts = new Guid(GUID_DEVINTERFACE_COMPORT);
        IntPtr hDeviceInfoSet = SetupDiGetClassDevs(
            ref guidComPorts, 0, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
        if (hDeviceInfoSet == IntPtr.Zero)
        {
            throw new Exception("Failed to get device information set for the COM ports");
        }

        try {
            
            List<DeviceInfo> devices = new List<DeviceInfo>();
            Int32 iMemberIndex = 0;
            while (true)
            {
                SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA();
                deviceInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
                bool success = SetupDiEnumDeviceInfo(hDeviceInfoSet, iMemberIndex, ref deviceInfoData);
                if (!success)
                {
                    // No more devices in the device information set
                    break;
                }

                DeviceInfo deviceInfo = new DeviceInfo();
                deviceInfo.name = GetDeviceName(hDeviceInfoSet, deviceInfoData);
                deviceInfo.decsription = GetDeviceDescription(hDeviceInfoSet, deviceInfoData);
                devices.Add(deviceInfo);

                iMemberIndex++;
            }
            return devices;
        }
        finally {
            SetupDiDestroyDeviceInfoList(hDeviceInfoSet);
        }
    }
    /// <summary>
    /// Get List of Modem
    /// </summary>
    /// <returns>List device info</returns>
    public static List<DeviceInfo> GetAllModem()
    {
        Guid guidComPorts = new Guid(GUID_DEVINTERFACE_MODEM);
        IntPtr hDeviceInfoSet = SetupDiGetClassDevs(
            ref guidComPorts, 0, IntPtr.Zero, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
        if (hDeviceInfoSet == IntPtr.Zero)
        {
            throw new Exception("Failed to get device information set for the COM ports");
        }

        try
        {

            List<DeviceInfo> devices = new List<DeviceInfo>();
            Int32 iMemberIndex = 0;
            while (true)
            {
                SP_DEVINFO_DATA deviceInfoData = new SP_DEVINFO_DATA();
                deviceInfoData.cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA));
                bool success = SetupDiEnumDeviceInfo(hDeviceInfoSet, iMemberIndex, ref deviceInfoData);
                if (!success)
                {
                    // No more devices in the device information set
                    break;
                }

                DeviceInfo deviceInfo = new DeviceInfo();
                deviceInfo.name = GetDeviceName(hDeviceInfoSet, deviceInfoData);
                deviceInfo.decsription = GetDeviceDescription(hDeviceInfoSet, deviceInfoData);
                devices.Add(deviceInfo);

                iMemberIndex++;
            }
            return devices;
        }
        finally
        {
            SetupDiDestroyDeviceInfoList(hDeviceInfoSet);
        }
    }
    /// <summary>
    /// Get device name 
    /// </summary>
    /// <param name="pDevInfoSet">IntPtr</param>
    /// <param name="deviceInfoData">SP_DEVINFO_DATA</param>
    /// <returns>string devicename</returns>
    private static string GetDeviceName(IntPtr pDevInfoSet, SP_DEVINFO_DATA deviceInfoData)
    {
        IntPtr hDeviceRegistryKey = SetupDiOpenDevRegKey(pDevInfoSet, ref deviceInfoData,
            DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
        if (hDeviceRegistryKey == IntPtr.Zero)
        {
            throw new Exception("Failed to open a registry key for device-specific configuration information");
        }

        StringBuilder deviceNameBuf = new StringBuilder(256);
        try
        {
            uint lpRegKeyType;
            uint length = (uint)deviceNameBuf.Capacity;
            int result = RegQueryValueEx(hDeviceRegistryKey, "PortName", 0, out lpRegKeyType, deviceNameBuf, ref length);
            if (result != 0)
            {
                throw new Exception("Can not read registry value PortName for device " + deviceInfoData.ClassGuid);
            }
        }
        finally
        {
            RegCloseKey(hDeviceRegistryKey);
        }

        string deviceName = deviceNameBuf.ToString();
        return deviceName;
    }
    /// <summary>
    /// Get Device Description
    /// </summary>
    /// <param name="hDeviceInfoSet"></param>
    /// <param name="deviceInfoData"></param>
    /// <returns></returns>
    private static string GetDeviceDescription(IntPtr hDeviceInfoSet, SP_DEVINFO_DATA deviceInfoData)
    {
        StringBuilder descriptionBuf = new StringBuilder(256);
        uint propRegDataType;
        uint length = (uint)descriptionBuf.Capacity;
        bool success = SetupDiGetDeviceRegistryProperty(hDeviceInfoSet, ref deviceInfoData, SPDRP_DEVICEDESC,
            out propRegDataType, descriptionBuf, length, out length);
        if (!success)
        {
            throw new Exception("Can not read registry value PortName for device " + deviceInfoData.ClassGuid);
        }
        string deviceDescription = descriptionBuf.ToString();
        return deviceDescription;
    }

}

}
